import java.util.Arrays;

public class IntegerBreak {

    public int integerBreak(int n) {
        int[][] dp = new int[n + 1][n + 1];
        for (int i = 0; i < n + 1; i++) {
            Arrays.fill(dp[i], -1);
        }
        return process(0, n, dp, n);
    }

    public int process(int i, int rest, int[][] dp, int n) {
        if (dp[i][rest] != -1) return dp[i][rest];
        if (i == n) {
            dp[i][rest] = rest == 0 ? 1 : 0;
            return dp[i][rest];
        }
        int max = Integer.MIN_VALUE;
        for (int j = 1; j < n; j++) {
            if (rest - j >= 0) {
                max = Math.max(process(i + 1, rest - j, dp, n) * j, Math.max(process(i + 1, rest, dp, n), max));
            } else {
                max = Math.max(process(i + 1, rest, dp, n), max);
            }
        }
        dp[i][rest] = max == Integer.MIN_VALUE ? 0 : max;
        return dp[i][rest];
    }

    public int integerBreak1(int n) {
        int[][] dp = new int[n + 1][n + 1];
        dp[n][0] = 1;
        for (int i = n - 1; i >= 0; i--) {
            for (int j = 0; j < n + 1; j++) {
                int max = Integer.MIN_VALUE;
                for (int k = 1; k < n; k++) {
                    if (j - k >= 0) {
                        max = Math.max(dp[i + 1][j - k] * k, Math.max(dp[i + 1][j], max));
                    } else {
                        max = Math.max(max, dp[i + 1][j]);
                    }
                }
                dp[i][j] = max == Integer.MIN_VALUE ? 0 : max;
            }
        }
        return dp[0][n];
    }

    public int integerBreak2(int n) {
        int[] dp = new int[n + 1];
        for (int i = 2; i < n + 1; i++) {
            int max = 0;
            for (int j = 1; j < i; j++) {
                max = Math.max(max, Math.max(dp[i - j] * j, j * (i - j)));
            }
            dp[i] = max;
        }
        return dp[n];
    }
}
